
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;


public class GUI {	
	//main GUI features being used
	private static Shell shell;
	private static Canvas canvas;
	private static Display display;
	private static Menu menu;
	
	//GUI widgets
	private static List robots,files;
	private static Text name;
	private static Combo type;
	private static Button armAdd, smartAdd, addButton;
	
	private static Simulation sim = new Simulation();//in charge of all robots and boxes
	private static DrawEnvironment drawEnv = new DrawEnvironment(sim);//draws robots and boxes to canvas
	private static GuiCommands gCmnds;//runs all commands that are sent from GUI
	private static Programs progs = new Programs();
	
	private static boolean run = false;//boolean states if simulation should run or stop
	private static boolean moveRobot = false; //is there a robot to be moved
	private static Robot robot = null; // robot to be moved by mouse
//	private static MyThread thread = null; //thread that runs timer to redraw canvas every second
	
	public enum Addition{ARM, SMART, ALL, NONE};//types of additions
	
	//returns state of simulation - run / stop
	public static boolean run() {return run;}
	//stops simulation
	public static void stopSim() {run = false;}
	//starts simulation
	public static void startSim() {run = true;}
	
	
	/**_______________________________________________________________________________________
	//timerTask - redraws canvas
	private static class RedrawTask extends TimerTask{
		 Canvas c;
		 Display d;
		 
		 public void setCanvas(Canvas c){
		  this.c=c;
		  d=c.getDisplay();
		 }
		 @Override
		 public void run() {  
			 d.asyncExec(new Runnable(){
				 public void run() {
					 if(!c.isDisposed()){
						 c.redraw();
						 c.update();
					 }
				 }
			 });
		 }
		}
	
	// a thread that runs the timerTask every second
	private static class MyThread extends Thread{
	 private RedrawTask rt;
	 private Timer ti;
		public void run(){
		 	rt = new RedrawTask();
		    rt.setCanvas(canvas);
			ti = new Timer();
			ti.scheduleAtFixedRate(rt, 0, 1000);
	     }
	 public void end(){
		 rt.cancel();
		 ti.cancel();
	 }
	}
	/**_________________________________________________________________________________________**/
	
	
	//inserting robot and file lists
	private static void initLists(Group g){
		// headlines:
		new Label(g,SWT.NONE).setText("Robots List");
		new Label(g,SWT.NONE);	// blank
		new Label(g,SWT.NONE).setText("Files List");
		
		/*** list, button, list ***/
		// list of robots
		robots=new List(g,SWT.BORDER | SWT.V_SCROLL);
		robots.setLayoutData(new GridData(150,80));
		//button to connect robot to file
		final Button b = new Button(g,SWT.PUSH);
		b.setText("<-");
		//list of files
		files=new List(g,SWT.BORDER | SWT.V_SCROLL);		
		files.setLayoutData(new GridData(150,80));
		File f=new File(".");
		files.setItems(f.list());
		
		//listener for <- button
		 Listener listener = new Listener() {
	    	 public void handleEvent(Event event){
	    		 if(event.widget == b){
	    			//get name of robot (split in case robot has file assigned already)
	    			String robot_n = robots.getSelection()[0].split(" ")[0]; 
	    			String file_n = files.getSelection()[0];			
	    			//if is able to assign then set file name on robot list
	    			if(gCmnds.assign(robot_n, file_n)){
	    				robots.setItem(robots.getSelectionIndex(), robot_n + " - " + file_n);
	    			}
	    		}
	    	 }
	    };
	    	  
	    b.addListener(SWT.Selection, listener);
	}
	
	//inserting adding robot part - name, type and addition
	private static void initAddingRobot(Group g){
		//robot name
		new Label(g,SWT.NONE).setText("Name");
		name = new Text(g, SWT.SINGLE | SWT.BORDER);
		name.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		//arm addition check button
		armAdd = new Button(g, SWT.CHECK);
		armAdd.setText("add arm");
		armAdd.setSelection(false);
		//add button
		addButton = new Button(g, SWT.PUSH);
		addButton.setText("Add"); 
	    addButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 2));
		//robot type
		new Label(g,SWT.NONE).setText("Type");
		type = new Combo(g, SWT.SINGLE | SWT.BORDER);
		type.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
		String[] items = {"RV1", "RV2", "Aibo"};
		type.setItems(items);
		type.setText("Aibo");
		//smart kit addition - check button
		smartAdd = new Button(g, SWT.CHECK);
		smartAdd.setText("smart kit");
		smartAdd.setSelection(false);
	
		//listener for ADD button
		Listener listener = new Listener() {
	    	 public void handleEvent(Event event){
	    		 if(event.widget == addButton){
	    			//check that entered name and type
	    			if(name.getText() == ""){
	    				errorMessage("Enter information");
	    				return;
	    			}
	    			//check if addition was made
	    			Addition add = Addition.NONE;
	    			if(armAdd.getSelection()){
	    				 if(smartAdd.getSelection())
	    					 add = Addition.ALL;
	    				 else
	    					 add = Addition.ARM;
	    			 }
	    			 else if(smartAdd.getSelection())
	    				 add = Addition.SMART;
	    			 
	    			 //create robot
	    			 if(gCmnds.addRobot(name.getText(), type.getText(), add))
	    				 robots.add(name.getText());//add to robots list if was able to create
	    		}
	    	 }
	    };
	    	  
	    addButton.addListener(SWT.Selection, listener);
	
	}
	    
	public static void main(String[] args) {
	    display = new Display();
	    shell = new Shell(display);
	    shell.setLayout(new GridLayout(2,false));
	    shell.setText("Advanced Programming exercise 1");
	    shell.setSize(700, 600);
	    
	    

	    // -------- Main window parts------------
	   
	    
		//menu
		menu = new Menu(shell, SWT.BAR); //initialize menu bar
		//set menu items
		MenuItem fileItem = new MenuItem(menu, SWT.CASCADE);
		fileItem.setText("File");
		setFileMenu(fileItem);
		
		MenuItem boxItem = new MenuItem(menu, SWT.CASCADE);
		boxItem.setText("Box");
		setBoxMenu(boxItem);
		    
		shell.setMenuBar(menu);
			
	    
	    // ==== Group 1
	    //set the group of create robot
	    Group group1=new Group(shell,SWT.SHADOW_IN);
	    group1.setText("Create Robot");
	    // makes it to take as much space it can:
	    group1.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
	    group1.setLayout(new GridLayout(4, false));
	    //insert components to group 1
	    initAddingRobot(group1);
	    
	    // ==== Group 2
	    //set the group of the lists
	    Group group2=new Group(shell,SWT.SHADOW_IN);
	    // set the group layout to be 3 cols 
	    group2.setLayout(new GridLayout(3,false));
	    // init the group components
	    initLists(group2);	// init the lists into group2 
	    
	    // ==== the big drawing Canvas
	    canvas = new Canvas(shell,SWT.BORDER);
	    // set the canvas to take 2 cells
	    canvas.setLayoutData(new GridData(SWT.FILL,SWT.FILL,false,true,2,1));
	    canvas.setBackground(display.getSystemColor(1));
	    canvas.addPaintListener(drawEnv); 
	   
	    //mouse listener to allow dragging robots around (one at a time)
    	canvas.addMouseListener(new MouseListener(){
    		public void mouseDown(MouseEvent e) {
    			//go over robots and find robot that mouse is on
    			Robot r = sim.getRobotAt(setCoor(new Position(e.x, e.y)));
    			if(r != null){
    				robot = r;//set to robot that is being moved
    				moveRobot = true;
    			}
    	 }
    	 public void mouseUp(MouseEvent e) {
    	 		moveRobot = false; //set to not moving a robot currently
    	 		robot = null;
    	 }
    	 public void mouseDoubleClick(MouseEvent e){}
    	});
    	
    	canvas.addMouseMoveListener(new MouseMoveListener(){
    		 public void mouseMove(MouseEvent e) {
    			 //if robot is being clicked on - then set it's position to where mouse is moving
    			 if(moveRobot){
    				 //check if robot's program is not being run
    				 if(!robot.hasFile() || !run){
    					 robot.setCurrentPosition(setCoor(new Position(e.x, e.y)));
    					 canvas.redraw();
    				 }
    			 }
    		 }    
    		});


    	//== initialize commands class and menu(contains file and box)
	    gCmnds = new GuiCommands(sim, canvas, shell, progs);
	    	   
	    
	    // --------- end of main window part --------
	   
	    
	    
	    shell.open();
	    // Set up the event loop.
	    while (!shell.isDisposed()) {
	      if (!display.readAndDispatch()) {
	        // If no more entries in the event queue
	        display.sleep();
	      }
	    }
	    //if(thread != null)
	   // 	thread.end();//end timer thread
	    run = false; //stops all threads on programs
	    display.dispose();
	}//end of MAIN
	
	
	/** methods that set menu items_________________________________________________________________***/
	//method sets file menu in menu bar
	private static void setFileMenu(MenuItem fileItem){
	    Menu fileMenu = new Menu(menu);
	    fileItem.setMenu(fileMenu);
	    
	    //set texts
	    MenuItem startSimItem = new MenuItem(fileMenu, SWT.NONE);
	    startSimItem.setText("Start Simulation");
	    MenuItem stopSimItem = new MenuItem(fileMenu, SWT.NONE);
	    stopSimItem.setText("Stop Simulation");
	    
	    new MenuItem(fileMenu, SWT.SEPARATOR); //line separator
	    MenuItem exitItem = new MenuItem(fileMenu, SWT.NONE);
	    exitItem.setText("Exit");
	    
	    
	    //start simulation listener
	    startSimItem.addSelectionListener(new SelectionAdapter(){
	    	public void widgetSelected(SelectionEvent event) {
	    		if(!run){ //if isn't running already
		    		run = true;
	    			gCmnds.simulate();
	    		}
	    	}
	    });
		    
		  //start simulation listener
		    stopSimItem.addSelectionListener(new SelectionAdapter(){
		    	public void widgetSelected(SelectionEvent event) {
		    		  GUI.run = false;
		    		  gCmnds.stopSimulation();
		    	}
		    });
		    
		    //exit listener
		    exitItem.addSelectionListener(new SelectionAdapter(){
		    	public void widgetSelected(SelectionEvent event) {
		    		  //close shell when exit is called
				      shell.close();
		    	}
		    });
		}
	
	
	//method sets box menu
	private static void setBoxMenu(MenuItem boxItem){
		 //box menu
	    Menu boxMenu = new Menu(menu);
	    boxItem.setMenu(boxMenu);
	    
	    MenuItem AddBoxItem = new MenuItem(boxMenu, SWT.NONE);
	    AddBoxItem.setText("Add Box");
	
	
		//Add Box listener
		AddBoxItem.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent event) {
				gCmnds.addBox();
				
			}
		});
	}
	/**_____________________________________________________________________________________**/
	
	
	//methods prints error to message box using separate thread
	public static void errorMessage(final String msg){
		Thread thread = new Thread(){
			public void run(){
				display.syncExec(new Runnable(){
					public void run(){
						MessageBox mb = new MessageBox(shell);
						mb.setText("Error");
						mb.setMessage(msg);
						mb.open();
					}
				});
			}
			
		};
		thread.start();
	}
	
	//receives coordinate according to canvas and changes it to be according to center
	public static Position setCoor(Position p){
		return new Position(p.x - (canvas.getSize().x)/2, -1 *(p.y - (canvas.getSize().y)/2));
	}


}
